﻿using System;
using System.Runtime.CompilerServices;
using Newtonsoft.Json;

namespace Ecobee.Net
{	 
	[JsonConverter(typeof(ApiTemperatureConverter))]
	public class ApiTemperature : ApiObject, IComparable, IFormattable, IComparable<ApiTemperature>, IEquatable<ApiTemperature>
	{
		private Int64 _internalValue = 0;
		private bool _hasValue = false;

		/// <summary>
		/// Creates an instance of Ecobee.Net.ApiTemperature initialized to
		/// a temperature of zero.
		/// </summary>
		public ApiTemperature()
		{
		}

		/// <summary>
		/// Creates an instance of Ecobee.Net.ApiTemperature initialized to
		/// the specified Real Temperature.
		/// </summary>
		/// <param name="value">A System.Double that specifies the actual temperature.</param>
		public ApiTemperature(float? value)
		{
			if (value.HasValue)
			{
				this.RealTemperature = value.Value;
			}
		}

		/// <summary>
		/// Creates an instance of Ecobee.Net.ApiTemperature initialized to
		/// the specified Thermostat Temperature.
		/// </summary>
		/// <param name="value">A System.Int32 that specifies the thermostat temperature.</param>
		public ApiTemperature(Int32? value)
		{
			if (value.HasValue)
			{
				this.ThermostatTemperature = value.Value;
			}
		}

		/// <summary>
		/// Creates an instance of Ecobee.Net.ApiTemperature initialized to
		/// the specified Thermostat Temperature.
		/// </summary>
		/// <param name="value">A System.Int64 that specifies the thermostat temperature.</param>
		[JsonConstructor()]
		public ApiTemperature(Int64? value)
		{
			if (value.HasValue)
			{
				this.ThermostatTemperature = value.Value;
			}
		}

		/// <summary>
		/// Gets/sets the temperature in integer format. This returned by API calls
		/// and is expected when passing to an API call. The temperature is in a 
		/// System.Int32 value that is a multiple of ten times the real value.
		/// </summary>
		public Int64 ThermostatTemperature
		{
			get
			{
				return _internalValue;
			}
			set
			{
				this.HasValue = true;
				_internalValue = value;
			}
		}

		/// <summary>
		/// Get/sets the actual temperature.
		/// </summary>
		public float RealTemperature
		{
			get
			{
				return _internalValue / 10F;
			}
			set
			{
				this.HasValue = true;
				_internalValue = (Int64)(value * 10F);
			}
		}

		/// <summary>
		/// Gets a value that indicates if this instance
		/// has a value (True) or if it was initialized with a null
		/// value (False).
		/// </summary>
		public bool HasValue
		{
			get
			{
				return _hasValue;
			}
			internal set
			{
				_hasValue = value;
			}
		}

		#region Implicit Conversions
		/// <summary>
		/// Converts the specified Ecobee.Net.ApiTemperature to its
		/// equivalent System.Double value.
		/// </summary>
		/// <param name="item">The Ecobee.Net.ApiTemperature to convert.</param>
		/// <returns>A System.Double representing the real temperature in the 
		/// Ecobee.Net.ApiTemperature object.</returns>
		public static implicit operator double(ApiTemperature item)
		{
			return item.RealTemperature;
		}

		/// <summary>
		/// Converts the specified Ecobee.Net.ApiTemperature to its
		/// equivalent System.Single value.
		/// </summary>
		/// <param name="item"></param>
		/// <returns></returns>
		public static implicit operator float(ApiTemperature item)
		{
			return item.RealTemperature;
		}

		/// <summary>
		/// Converts the specified System.Double to its
		/// equivalent Ecobee.Net.ApiTemperature value.
		/// </summary>
		/// <param name="value">The System.Double value to convert.</param>
		/// <returns>A new Ecobee.Net.ApiTemperature initialized with real temperature
		/// specified in the System.Double value.</returns>
		public static implicit operator ApiTemperature(float value)
		{
			return new ApiTemperature(value);
		}

		/// <summary>
		/// Converts the specified Ecobee.Net.ApiTemperature to its
		/// equivalent System.Int64 value.
		/// </summary>
		/// <param name="item">The Ecobee.Net.ApiTemperature to convert.</param>
		/// <returns>A System.Int64 representing the thermostat temperature in the 
		/// Ecobee.Net.ApiTemperature object.</returns>
		public static implicit operator Int64(ApiTemperature item)
		{
			return item.ThermostatTemperature;
		}

		/// <summary>
		/// Converts the specified System.Int64 to its
		/// equivalent Ecobee.Net.ApiTemperature value.
		/// </summary>
		/// <param name="value">The System.Double value to convert.</param>
		/// <returns>A new Ecobee.Net.ApiTemperature initialized with thermostat temperature
		/// specified in the System.Int64 value.</returns>
		public static implicit operator ApiTemperature(Int64 value)
		{
			return new ApiTemperature(value);
		}

		/// <summary>
		/// Converts the specified Ecobee.Net.ApiTemperature to its
		/// equivalent System.Int32 value.
		/// </summary>
		/// <param name="item">The Ecobee.Net.ApiTemperature to convert.</param>
		/// <returns>A System.Int32 representing the thermostat temperature in the 
		/// Ecobee.Net.ApiTemperature object.</returns>
		public static implicit operator Int32(ApiTemperature item)
		{
			return Convert.ToInt32(item.ThermostatTemperature);
		}

		/// <summary>
		/// Converts the specified System.Int32 to its
		/// equivalent Ecobee.Net.ApiTemperature value.
		/// </summary>
		/// <param name="value">The System.Double value to convert.</param>
		/// <returns>A new Ecobee.Net.ApiTemperature initialized with thermostat temperature
		/// specified in the System.Int32 value.</returns>
		public static implicit operator ApiTemperature(Int32 value)
		{
			return new ApiTemperature(value);
		}
		#endregion

		/// <summary>
		/// Returns a string that represents the current object.
		/// </summary>
		/// <returns>A string that represents the current object.</returns>
		public override string ToString()
		{
			return string.Format("{0:#,##0.0}", this.RealTemperature);
		}

		#region Static Members
		public static ApiTemperature Empty
		{
			get
			{
				return new ApiTemperature(null);
			}
		}

		/// <summary>
		/// Converts the specified string representation of a temperature to its 
		/// Ecobee.Net.ApiTemperature equivalent.
		/// </summary>
		/// <param name="s">A string containing a time to convert.</param>
		/// <returns>A Ecobee.Net.ApiTemperature object that is equivalent to the time contained in s.</returns>
		public static ApiTemperature Parse(string s)
		{
			ApiTemperature returnValue = 0;

			if (!ApiTemperature.TryParse(s, out returnValue))
			{
				throw new FormatException();
			}

			return returnValue;
		}

		/// <summary>
		/// Converts the specified string representation of a temperature to its
		/// equivalent Ecobee.Net.ApiTemperature and returns a value that indicates whether 
		/// the conversion succeeded.
		/// </summary>
		/// <param name="s">A string containing a time to convert.</param>
		/// <param name="result">An Ecobee.Net.ApiTemperature object that is equivalent to the time contained in s.</param>
		/// <returns>True if the parameter s was parsed successfully; False otherwise.</returns>
		public static bool TryParse(string s, out ApiTemperature result)
		{
			bool returnValue = false;
			result = 0;

			if (!string.IsNullOrEmpty(s))
			{
				if (s.Contains("."))
				{
					float parsedValue = 0;

					if (float.TryParse(s, out parsedValue))
					{
						result = parsedValue;
						returnValue = true;
					}
				}
				else
				{
					Int32 parsedValue = 0;

					if (Int32.TryParse(s, out parsedValue))
					{
						result = parsedValue;
						returnValue = true;
					}
				}
			}

			return returnValue;
		}

		/// <summary>
		/// Determines if the specified string representation of a temperature can be parsed to
		/// its equivalent Ecobee.Net.ApiTemperature object.
		/// </summary>
		/// <param name="s">A string containing a time to convert.</param>
		/// <returns>Returns True if the parameter s can be parsed successfully; False otherwise.</returns>
		public static bool CanParse(string s)
		{
			bool returnValue = false;

			ApiTemperature parsedResult = 0;
			returnValue = ApiTemperature.TryParse(s, out parsedResult);

			return returnValue;
		}
		#endregion

		#region IComparable
		/// <summary>
		/// Compares this instance with a specified object and indicates
		/// whether this instance precedes, follows, or appears in the same position
		/// as the specified System.Angle.
		/// </summary>
		/// <param name="obj">The object to compare with this instance.</param>
		/// <returns>A 32-bit signed integer that indicates whether this instance precedes,
		/// follows, or appears in the same position as the value parameter. Value 
		/// Condition Less than zero: This instance precedes obj. Zero: This instance
		/// has the same position as obj. Greater than zero: This instance
		/// follows obj or obj is null.</returns>
		public int CompareTo(object obj)
		{
			int returnValue = 1;

			if (obj is ApiTemperature)
			{
				returnValue = this.RealTemperature.CompareTo(((ApiTemperature)obj).RealTemperature);
			}

			return returnValue;
		}
		#endregion

		#region IComparable<ApiTemperature>
		/// <summary>
		/// Compares this instance with a specified Ecobee.Net.ApiTemperature object
		/// and indicates whether this instance precedes, follows, or appears in the
		/// same position as the specified Ecobee.Net.ApiTemperature.
		/// </summary>
		/// <param name="other">The Ecobee.Net.ApiTemperature to compare with this instance.</param>
		/// <returns>A 32-bit signed integer that indicates whether this instance precedes,
		/// follows, or appears in the same position as the value parameter. Value 
		/// Condition Less than zero: This instance precedes obj. Zero: This instance
		/// has the same position as obj. Greater than zero: This instance
		/// follows other or other is null.</returns>
		public int CompareTo(ApiTemperature other)
		{
			int returnValue = 1;

			if (other != null)
			{
				returnValue = this.RealTemperature.CompareTo(other.RealTemperature);
			}

			return returnValue;
		}
		#endregion

		#region IFormattable
		/// <summary>
		/// Converts the numeric value of this instance to its equivalent string representation
		/// using the specified culture-specific format information.
		/// </summary>
		/// <param name="format">A numeric format string.</param>
		/// <param name="formatProvider">An object that supplies culture-specific formatting information.</param>
		/// <returns>The string representation of the value of this instance as specified by format and provider.</returns>
		public string ToString(string format, IFormatProvider formatProvider)
		{
			return this.RealTemperature.ToString(format, formatProvider);
		}
		#endregion

		#region IEquatable<ApiTemperature>
		/// <summary>
		/// Specifies whether this Ecobee.Net.ApiTemperature and the specified 
		/// Ecobee.Net.ApiTemperature have the same value.
		/// </summary>
		/// <param name="other">The Ecobee.Net.ApiTemperature to compare to this instance.</param>
		/// <returns>True if the value of the other parameter is the same as this 
		/// Ecobee.Net.ApiTemperature; False otherwise</returns>
		public bool Equals(ApiTemperature other)
		{
			bool returnValue = false;

			if (other != null)
			{
				returnValue = this.RealTemperature.Equals(other.RealTemperature);
			}

			return returnValue;
		}
		#endregion

		public override bool Equals(object obj)
		{
			bool returnValue = false;

			if (obj is ApiTemperature)
			{
				returnValue = (this.RealTemperature == ((ApiTemperature)obj).RealTemperature);
			}

			return returnValue;
		}

		public override int GetHashCode()
		{
			return RuntimeHelpers.GetHashCode(this);
		}
	}
}
